#include "systick.h"

//Timer ticks
static __IO uint32_t systick = 0;

//timer handle list head.
static struct Timer *head_handle = NULL;

void systick_init(void)
{
    /* SystemFrequency / 1000    1ms中断一次
     * SystemFrequency / 100000	 10us中断一次
     * SystemFrequency / 1000000 1us中断一次
     */
    if (SysTick_Config(SystemCoreClock / 1000))
//    if (SysTick_Config(SystemCoreClock / 100000))
    {
        /* Capture error */
        while (1)
            ;
    }
}
/**
  * @brief  Initializes the timer struct handle.
  * @param  handle: the timer handle strcut.
  * @param  timeout_cb: timeout callback.
  * @param  repeat: repeat interval time.
  * @retval None
  */
void timer_init(struct Timer *handle, uint16_t time, void (*timeout_cb)(void), uint16_t repeat, void (*repeatend_cb)(void))
{
    handle->timeout = systick + time;
    handle->time = time;
    handle->timeout_cb = timeout_cb;
    handle->repeat = repeat;
    handle->repeatend_cb = repeatend_cb;
}

/**
  * @brief  Start the timer work, add the handle into work list.
  * @param  btn: target handle strcut.
  * @retval 0: succeed. -1: already exist.
  */
int timer_start(struct Timer *handle)
{
    struct Timer *target = head_handle;
    while (target)
    {
        if (target == handle)
            return -1; //already exist.
        target = target->next;
    }
    handle->next = head_handle;
    head_handle = handle;
    return 0;
}

/**
  * @brief  Stop the timer work, remove the handle off work list.
  * @param  handle: target handle strcut.
  * @retval None
  */
void timer_stop(struct Timer *handle)
{
    struct Timer **curr;
    for (curr = &head_handle; *curr;)
    {
        struct Timer *entry = *curr;
        if (entry == handle)
        {
            *curr = entry->next;
        }
        else
            curr = &entry->next;
    }
}

/**
  * @brief  main loop.
  * @param  None.
  * @retval None
  */
void timer_loop(void)
{
    struct Timer *target;
    for (target = head_handle; target; target = target->next)
    {
        //fix bug when ticks overflow
        if ((int)((uint32_t)(target->timeout - systick)) <= 0)
        {
            if (target->repeat == 0)
            {
                timer_stop(target);
                target->repeatend_cb();
            }
            else
            {
                target->timeout = systick + target->time;
                //if target->repeat == 0xFFFF,forever loop
                if (target->repeat != LOOP_FOREVER)
                {
                    --target->repeat;
                }
                target->timeout_cb();
            }
        }
    }
}

__weak void swm_inctick(void)
{
    systick++;
}

__weak uint32_t swm_gettick(void)
{
    return systick;
}

__weak void swm_delay(__IO uint32_t delay)
{
    uint32_t tickstart = 0;
    tickstart = swm_gettick();
    while ((swm_gettick() - tickstart) < delay)
    {
        ;
    }
}

__weak void SysTick_Handler_cb(void)
{
}

void SysTick_Handler(void)
{
    swm_inctick();
    SysTick_Handler_cb();
}

/*********************************************END OF FILE**********************/
